//
//  FMDBManager.m
//  ZZLCrazyBuy
//
//  Created by gorson on 3/17/15.
//  Copyright (c) 2015 1000Phone. All rights reserved.
//

#import "FMDBManager.h"
#import <objc/runtime.h>

// 通过实体获取类名
#define KCLASS_NAME(model) [NSString stringWithUTF8String:object_getClassName(model)]
// 通过实体获取属性数组数目
#define KMODEL_PROPERTYS_COUNT [[self getAllProperties:model] count]
// 通过实体获取属性数组
#define KMODEL_PROPERTYS [self getAllProperties:model]

static FMDBManager * manager = nil;
@implementation FMDBManager

{
    FMDatabase *db; //数据库
}

// 单例
+ (FMDBManager *)sharedInstace
{
    if (manager == nil) {
        manager = [[FMDBManager alloc]init];
    }
    return manager;
}

// 获取沙盒路径
- (NSString *)databaseFilePath
{
    
    NSArray *filePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentPath = [filePath objectAtIndex:0];
    NSLog(@"%@",filePath);
    NSString *dbFilePath = [documentPath stringByAppendingPathComponent:@"db.sqlite"];
    NSLog(@"home:%@",NSHomeDirectory());
    return dbFilePath;
    
}

// 创建数据库
- (void)creatDatabase
{
    db = [FMDatabase databaseWithPath:[self databaseFilePath]];
}

- (void)creatTable:(id)model
{
    
    
    //先判断数据库是否存在，如果不存在，创建数据库
    if (!db) {
        [self creatDatabase];
    }
    //判断数据库是否已经打开，如果没有打开，提示失败
    if (![db open]) {
        NSLog(@"数据库打开失败");
        return;
    }
    
    //为数据库设置缓存，提高查询效率
    [db setShouldCacheStatements:YES];
    
    //判断数据库中是否已经存在这个表，如果不存在则创建该表
    if (![db tableExists:KCLASS_NAME(model)]) {
//   create table weibomodel (id integer primary key,userID text,userClass text,screenName text,name text,province text,city text,location text...)
//（1）获取类名作为数据库表名
//（2）获取类的属性作为数据表字段
        
        // 1.创建表语句头部拼接
        NSString *creatTableStrHeader = [NSString stringWithFormat:@"create table %@(id INTEGER PRIMARY KEY",KCLASS_NAME(model)];
        
        // 2.创建表语句中部拼接
        NSString *creatTableStrMiddle =[NSString string];
        for (int i = 0; i < KMODEL_PROPERTYS_COUNT; i++) {
            creatTableStrMiddle = [creatTableStrMiddle stringByAppendingFormat:@",%@ TEXT",[KMODEL_PROPERTYS objectAtIndex:i]];
        }
        // 3.创建表语句尾部拼接
        NSString *creatTableStrTail =[NSString stringWithFormat:@")"];
        // 4.整句创建表语句拼接
        NSString *creatTableStr = [NSString string];
        creatTableStr = [creatTableStr stringByAppendingFormat:@"%@%@%@",creatTableStrHeader,creatTableStrMiddle,creatTableStrTail];
        [db executeUpdate:creatTableStr];
        
        NSLog(@"创建完成");
    }
    //    关闭数据库
    [db close];
}

/**
 *  数据库增加或更新实体
 *
 *  @param model 实体
 */
-(void)insertAndUpdateModelToDatabase:(id)model
{
    // 判断数据库是否存在
    if (!db) {
        [self creatDatabase];
    }
    
    // 判断数据库能否打开
    if (![db open]) {
        NSLog(@"数据库打开失败");
        return;
    }
    // 设置数据库缓存
    [db setShouldCacheStatements:YES];
    
    // 判断是否存在对应的userModel表
    if(![db tableExists:KCLASS_NAME(model)])
    {
        [self creatTable:model];
    }
    
    //以上操作与创建表是做的判断逻辑相同
    //现在表中查询有没有相同的元素，如果有，做修改操作
//  select *from tableName where userID = ?
    
    // 拼接查询语句头部
    NSString *selectStrHeader = [NSString stringWithFormat:@"select * from %@ where ",KCLASS_NAME(model)];
    // 拼接查询语句尾部
    NSString *selectStrTail = [NSString stringWithFormat:@"%@ = ?",[KMODEL_PROPERTYS objectAtIndex:0]];
    // 整个查询语句拼接
    NSString *selectStr = [NSString string];
    selectStr = [selectStr stringByAppendingFormat:@"%@%@",selectStrHeader,selectStrTail];
    FMResultSet * resultSet = [db executeQuery:selectStr,[model valueForKey:[KMODEL_PROPERTYS objectAtIndex:0]]];
    
    if([resultSet next])
    {
//        update tableName set userID = ?,userClass = ?,screenName = ?,name = ?,province = ?,city = ?,location = ? where userID = ?
        
        // 拼接更新语句的头部
        NSString *updateStrHeader = [NSString stringWithFormat:@"update %@ set ",KCLASS_NAME(model)];
        // 拼接更新语句的中部
        NSString *updateStrMiddle = [NSString string];
        for (int i = 0; i< KMODEL_PROPERTYS_COUNT; i++) {
            updateStrMiddle = [updateStrMiddle stringByAppendingFormat:@"%@ = ?",[KMODEL_PROPERTYS objectAtIndex:i]];
            if (i != KMODEL_PROPERTYS_COUNT -1) {
                updateStrMiddle = [updateStrMiddle stringByAppendingFormat:@","];
            }
        }
        // 拼接更新语句的尾部
        
        NSString *updateStrTail = [NSString stringWithFormat:@" where %@ = ?",[KMODEL_PROPERTYS objectAtIndex:0]];
        // 整句拼接更新语句
        NSString *updateStr = [NSString string];
        updateStr = [updateStr stringByAppendingFormat:@"%@%@%@",updateStrHeader,updateStrMiddle,updateStrTail];
        NSMutableArray *propertyArray = [NSMutableArray array];
        
        for (int i = 0; i < KMODEL_PROPERTYS_COUNT; i++) {
            NSString *midStr = [model valueForKey:[KMODEL_PROPERTYS objectAtIndex:i]];
            // 判断属性值是否为空
            if (midStr == nil) {
                midStr = @"none";
            }
            [propertyArray addObject:midStr];
        }
        [propertyArray addObject:[model valueForKey:[KMODEL_PROPERTYS objectAtIndex:0]]];
//        [db executeUpdate:updateStr withArgumentsInArray:propertyArray];
        BOOL b= [db executeUpdate:updateStr withArgumentsInArray:propertyArray];
        if (b) {
            NSLog(@"insert succeed");
        }
    }
    //向数据库中插入一条数据
    else{
        // 拼接插入语句的头部
//        insert into tableName ( userID,userClass,screenName,name,province,city,location) values (?,?,?,?,?,?,?)
        
        NSString *insertStrHeader = [NSString stringWithFormat:@"INSERT INTO %@ (",KCLASS_NAME(model)];
        // 拼接插入语句的中部1
        NSString *insertStrMiddleOne = [NSString string];
        for (int i = 0; i < KMODEL_PROPERTYS_COUNT; i++) {
            insertStrMiddleOne = [insertStrMiddleOne stringByAppendingFormat:@"%@",[KMODEL_PROPERTYS objectAtIndex:i]];
            if (i != KMODEL_PROPERTYS_COUNT -1) {
                insertStrMiddleOne = [insertStrMiddleOne stringByAppendingFormat:@","];
            }
        }
        // 拼接插入语句的中部2
        NSString *insertStrMiddleTwo = [NSString stringWithFormat:@") VALUES ("];
        // 拼接插入语句的中部3
        NSString *insertStrMiddleThree = [NSString string];
        for (int i = 0; i < KMODEL_PROPERTYS_COUNT; i++) {
            insertStrMiddleThree = [insertStrMiddleThree stringByAppendingFormat:@"?"];
            if (i != KMODEL_PROPERTYS_COUNT-1) {
                insertStrMiddleThree = [insertStrMiddleThree stringByAppendingFormat:@","];
            }
        }
        // 拼接插入语句的尾部
        NSString *insertStrTail = [NSString stringWithFormat:@")"];
        // 整句插入语句拼接
        NSString *insertStr = [NSString string];
        insertStr = [insertStr stringByAppendingFormat:@"%@%@%@%@%@",insertStrHeader,insertStrMiddleOne,insertStrMiddleTwo,insertStrMiddleThree,insertStrTail];
        NSMutableArray *modelPropertyArray = [NSMutableArray array];
        for (int i = 0; i < KMODEL_PROPERTYS_COUNT; i++) {
            NSString *str = [model valueForKey:[KMODEL_PROPERTYS objectAtIndex:i]];
            if (str == nil) {
                str = @"none";
            }
            [modelPropertyArray addObject: str];
        }
        
       BOOL b= [db executeUpdate:insertStr withArgumentsInArray:modelPropertyArray];
        if (b) {
            NSLog(@"insert succeed");
        }
        
    }
    //    关闭数据库
    [db close];
}

/**
 *  数据库对应实体
 *
 *  @param model 实体
 */
- (void)deleteModelInDatabase:(id)model
{
    // 判断是否创建数据库
    if (!db) {
        [self creatDatabase];
    }
    // 判断数据是否已经打开
    if (![db open]) {
        NSLog(@"数据库打开失败");
        return;
    }
    // 设置数据库缓存，优点：高效
    [db setShouldCacheStatements:YES];
    
    // 判断是否有该表
    if(![db tableExists:KCLASS_NAME(model)])
    {
        return;
    }
    // 删除操作
    // 拼接删除语句
    // delete from tableName where userId = ?
    
    NSString *deletStr = [NSString stringWithFormat:@"delete from %@ where %@ = ?",KCLASS_NAME(model),[KMODEL_PROPERTYS objectAtIndex:0]];
    [db executeUpdate:deletStr, [model valueForKey:[KMODEL_PROPERTYS objectAtIndex:0]]];
    // 关闭数据库
    [db close];
}

/**
 *  数据库对应实体
 *
 *  @param model 实体
 */
-(void)deleteAllModelInDatabase:(NSString *)modelName;
{
    // 判断是否创建数据库
    if (!db) {
        [self creatDatabase];
    }
    // 判断数据是否已经打开
    if (![db open]) {
        NSLog(@"数据库打开失败");
        return;
    }
    // 设置数据库缓存，优点：高效
    [db setShouldCacheStatements:YES];
    
    // 判断是否有该表
    if(![db tableExists:modelName])
    {
        return;
    }
    // 删除操作
    // 拼接删除语句
    // delete from tableName where userId = ?
    
    NSString *deletStr = [NSString stringWithFormat:@"drop table %@",modelName];
    [db executeUpdate:deletStr];
    // 关闭数据库
    [db close];
}

/**
 *  数据库查询所有实体
 *
 *  @param 所有实体
 */
- (NSArray *)selectModelArrayInDatabase:(id)model
{
//    select * from tableName
    if (!db) {
        [self creatDatabase];
    }
    
    if (![db open]) {
        NSLog(@"数据库打开失败");
        return nil;
    }
    
    [db setShouldCacheStatements:YES];
    
    if(![db tableExists:KCLASS_NAME(model)])
    {
        [self creatTable:model];
    }
    //定义一个可变数组，用来存放查询的结果，返回给调用者
    NSMutableArray *userModelArray = [NSMutableArray array];
    //定义一个结果集，存放查询的数据
    //拼接查询语句
    NSString *selectStr = [NSString stringWithFormat:@"select * from %@",KCLASS_NAME(model)];
    FMResultSet *resultSet = [db executeQuery:selectStr];
    //判断结果集中是否有数据，如果有则取出数据
    while ([resultSet next]) {
        // 用id类型变量的类去创建对象
        id modelResult = [[[model class]alloc] init];
        for (int i = 0; i < KMODEL_PROPERTYS_COUNT; i++) {
            [modelResult setValue:[resultSet stringForColumn:[KMODEL_PROPERTYS objectAtIndex:i]] forKey:[KMODEL_PROPERTYS objectAtIndex:i]];
        }
        //将查询到的数据放入数组中。
        [userModelArray addObject:modelResult];
    }
    // 关闭数据库
    [db close];
    
    return userModelArray;
}


/**
 *  传递一个model实体
 *
 *  @param model 实体
 *
 *  @return 实体的属性
 */
- (NSArray *)getAllProperties:(id)model
{
    u_int count;
    
    objc_property_t *properties  = class_copyPropertyList([model class], &count);
    
    NSMutableArray *propertiesArray = [NSMutableArray array];
    
    for (int i = 0; i < count ; i++)
    {
        const char* propertyName = property_getName(properties[i]);
        [propertiesArray addObject: [NSString stringWithUTF8String: propertyName]];
    }
    
    free(properties);
    return propertiesArray;
}
@end
